# -*- coding: utf-8 -*-
"""
稳定性模块测试
"""

import unittest
import time
import threading
from unittest.mock import patch, MagicMock

from src.stability import (
    ResourceMonitor, CircuitBreaker, RetryHandler, 
    ConcurrentProcessor, StabilityManager
)

class TestResourceMonitor(unittest.TestCase):
    """资源监控器测试"""
    
    def setUp(self):
        self.monitor = ResourceMonitor(max_memory_mb=100, max_cpu_percent=50.0)
    
    def tearDown(self):
        if self.monitor._monitoring:
            self.monitor.stop_monitoring()
    
    def test_start_stop_monitoring(self):
        """测试监控启动和停止"""
        self.assertFalse(self.monitor._monitoring)
        
        self.monitor.start_monitoring()
        self.assertTrue(self.monitor._monitoring)
        
        time.sleep(0.1)  # 让监控线程启动
        
        self.monitor.stop_monitoring()
        self.assertFalse(self.monitor._monitoring)

class TestCircuitBreaker(unittest.TestCase):
    """熔断器测试"""
    
    def setUp(self):
        self.breaker = CircuitBreaker(failure_threshold=2, recovery_timeout=1)
    
    def test_normal_operation(self):
        """测试正常操作"""
        def success_func():
            return "success"
        
        result = self.breaker.call(success_func)
        self.assertEqual(result, "success")
        self.assertEqual(self.breaker.state, 'CLOSED')
    
    def test_circuit_open(self):
        """测试熔断器开启"""
        def failure_func():
            raise Exception("test error")
        
        # 触发失败次数达到阈值
        for _ in range(2):
            with self.assertRaises(Exception):
                self.breaker.call(failure_func)
        
        self.assertEqual(self.breaker.state, 'OPEN')
        
        # 熔断器开启时应该拒绝请求
        with self.assertRaises(Exception):
            self.breaker.call(lambda: "should not execute")
    
    def test_circuit_recovery(self):
        """测试熔断器恢复"""
        def failure_func():
            raise Exception("test error")
        
        def success_func():
            return "success"
        
        # 触发熔断
        for _ in range(2):
            with self.assertRaises(Exception):
                self.breaker.call(failure_func)
        
        self.assertEqual(self.breaker.state, 'OPEN')
        
        # 等待恢复时间
        time.sleep(1.1)
        
        # 应该进入半开状态并成功恢复
        result = self.breaker.call(success_func)
        self.assertEqual(result, "success")
        self.assertEqual(self.breaker.state, 'CLOSED')

class TestRetryHandler(unittest.TestCase):
    """重试处理器测试"""
    
    def setUp(self):
        self.retry_handler = RetryHandler(max_retries=2, backoff_factor=0.1)
    
    def test_success_on_first_try(self):
        """测试第一次尝试成功"""
        def success_func():
            return "success"
        
        result = self.retry_handler.retry(success_func)
        self.assertEqual(result, "success")
    
    def test_success_after_retry(self):
        """测试重试后成功"""
        self.call_count = 0
        
        def retry_func():
            self.call_count += 1
            if self.call_count < 2:
                raise Exception("temporary error")
            return "success"
        
        result = self.retry_handler.retry(retry_func)
        self.assertEqual(result, "success")
        self.assertEqual(self.call_count, 2)
    
    def test_max_retries_exceeded(self):
        """测试超过最大重试次数"""
        def failure_func():
            raise Exception("persistent error")
        
        with self.assertRaises(Exception):
            self.retry_handler.retry(failure_func)

class TestConcurrentProcessor(unittest.TestCase):
    """并发处理器测试"""
    
    def setUp(self):
        self.processor = ConcurrentProcessor(max_workers=2, queue_size=10)
    
    def tearDown(self):
        if self.processor.running:
            self.processor.stop()
    
    def test_start_stop(self):
        """测试启动和停止"""
        self.assertFalse(self.processor.running)
        
        self.processor.start()
        self.assertTrue(self.processor.running)
        
        self.processor.stop()
        self.assertFalse(self.processor.running)
    
    def test_task_processing(self):
        """测试任务处理"""
        self.processor.start()
        
        def test_task(x):
            return x * 2
        
        # 提交任务
        success = self.processor.submit_task(test_task, 5)
        self.assertTrue(success)
        
        # 获取结果
        result = self.processor.get_result(timeout=2.0)
        self.assertIsNotNone(result)
        
        status, data = result
        self.assertEqual(status, 'success')
        self.assertEqual(data, 10)

class TestStabilityManager(unittest.TestCase):
    """稳定性管理器测试"""
    
    def setUp(self):
        self.manager = StabilityManager()
    
    def tearDown(self):
        if self.manager.active:
            self.manager.stop()
    
    def test_start_stop(self):
        """测试启动和停止"""
        self.assertFalse(self.manager.active)
        
        self.manager.start()
        self.assertTrue(self.manager.active)
        
        self.manager.stop()
        self.assertFalse(self.manager.active)
    
    @patch('psutil.virtual_memory')
    def test_batch_processing(self, mock_memory):
        """测试批量处理"""
        # Mock内存使用情况
        mock_memory.return_value = MagicMock(used=50 * 1024 * 1024)  # 50MB
        
        self.manager.start()
        
        def batch_processor(batch):
            return [x * 2 for x in batch]
        
        items = list(range(10))
        results = self.manager.process_batch(items, batch_processor, batch_size=3)
        
        expected = [x * 2 for x in items]
        self.assertEqual(len(results), len(expected))

if __name__ == '__main__':
    unittest.main()

